package cn.ad.service;

import cn.ad.common.DateUtils;
import cn.ad.exception.CampaignConfirmException;
import cn.ad.exception.CampaignValidateException;
import cn.ad.exception.StrategyRunningErrorException;
import cn.ad.handler.SqlSessionHandler;
import cn.ad.enumration.CampaignType;
import cn.ad.interceptor.PageParameter;
import cn.ad.model.CampaignModel;
import cn.ad.model.DropDownModel;
import cn.ad.model.ResultSetList;
import cn.ad.model.TimeUpdateModel;
import cn.ad.entity.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 订单服务层实现
 * 
 * @author yujuan.zhang
 * @from 2016-06-13
 * @since V1.0
 *
 */
@Service
public class CampaignService {

	private static Logger logger = LoggerFactory.getLogger(CampaignService.class);
	
	@Autowired
	private SqlSessionHandler sqlSessionHandler;
	@Autowired
	private AdvertiserService advertiserService;

	@Autowired
	private  AccountService accountService;

	/**
	 * 查询订单列表信息
	 * 
	 */
	public ResultSetList<CampaignModel> findCampaigns(String query, int offset, int limit, String sortby, String order,
													  Integer status, Integer feeType, Integer advertiserId, Integer agencyId) {
		Map<String, Object> map = new HashMap<>(6);
		map.put("sortby", sortby);
		map.put("key", query);
		map.put("order", order);
		map.put("status", status);
		map.put("feeType", feeType);
		map.put("advertiserId", advertiserId);
		map.put("agencyId", agencyId);
		PageParameter page = new PageParameter(offset, limit);
		List<CampaignModel> campaignList = sqlSessionHandler.selectList("campaignMapper.campaign:list:page", map, page);
		return new ResultSetList<>(page.getTotalCount(), campaignList);

	}

	public ResultSetList<CampaignModel> findCampaigns(Map<String,Object> searchMap){
		Integer offset= Integer.parseInt(searchMap.get("offset").toString());
		Integer limit= Integer.parseInt(searchMap.get("limit").toString());
		PageParameter page=new PageParameter(offset,limit);
		List<CampaignModel> campaignList = sqlSessionHandler.selectList("campaignMapper.campaigns:list:page", searchMap, page);
		return new ResultSetList<>(page.getTotalCount(), campaignList);
	}

	/**
	 * 根据订单ID查询单个订单信息
	 */
	public CampaignModel getCampaignById(Integer id) {
		CampaignModel model=sqlSessionHandler.selectOne("campaignMapper.selectById", id);
		if (model==null){
			logger.error("订单[{}]不存在", id);
			throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_NOTFOUND);
		}
		return model;
	}

	/**
	 * 订单新增
	 */
	@Transactional
	public Campaign addCampaign(Campaign campaign,Integer agencyId){
		if(isHasCampaign(campaign)){
			throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_REPEAT);
		}
		sqlSessionHandler.insert("campaignMapper.insert", campaign);
		Map<String,Object> map = new HashMap<String,Object>(2);
		map.put("agencyId", agencyId);
		map.put("balance", campaign.getBudget());
		sqlSessionHandler.update("agencyMapper.agency:balance:set", map);
		logger.info("添加了订单{}",campaign.getName());
		return campaign;
	}


	private void createCampaign(Campaign campaign) {
		if(isHasCampaign(campaign)){
			throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_REPEAT);
		}
		sqlSessionHandler.insert("campaignMapper.insert", campaign);
		if (campaign.getTags()==null){
			campaign.setTags(new String[]{CampaignType.COMMON.getDescription()});
		}
		//处理订单标签与订单之间的关系
		for (String tag:campaign.getTags()) {
			//(判断当前标签是否已存在)
			CampaignTag _tag=sqlSessionHandler.selectOne("campaignTagMapper.selectByName",tag);
			if (_tag==null){
				_tag=new CampaignTag();
				_tag.setName(tag);
				//如果标签不存在则创建新标签
				sqlSessionHandler.insert("campaignTagMapper.insert",_tag);
			}
			//创建订单-标签关系
			CampaignTagMap campaignTagMap = new CampaignTagMap();
			campaignTagMap.setCampaignId(campaign.getId());
			campaignTagMap.setTagId(_tag.getId());
			campaignTagMap.setStatus(1);
			sqlSessionHandler.insert("campaignTagMapMapper.insert",campaignTagMap);
		}
	}


	/**
	 * 新增订单
	 */
	public Campaign addCampaignByUserId(Campaign campaign,Integer userId) {
		this.createCampaign(campaign);
		//TODO 然后进行划账
		Advertiser advertiser=new Advertiser();
		advertiser.setId(campaign.getAdvertiserId());
		advertiser.setBalanceCash(new BigDecimal(campaign.getBudget()));
		advertiserService.updateAdvertiserAmount(advertiser,false);
		AccountCampaignRecords accountCampaignRecords = new AccountCampaignRecords();
		accountCampaignRecords.setAdvertiserId(advertiser.getId());
		accountCampaignRecords.setAmount(advertiser.getBalanceCash());
		accountCampaignRecords.setCampaignId(campaign.getId());
		accountCampaignRecords.setCreator(userId);
		accountCampaignRecords.setDealType(AccountTransferRecords.DEAL_TYPE_OUT);
		accountCampaignRecords.setDescription("FMobile调用");
		accountService.saveCampaginAccount(accountCampaignRecords);
		CampaignModel model=getCampaignById(campaign.getId());
		return model;
	}


	/**
	 * 订单更新
	 */
	@Transactional
	public void editCampaign(Campaign campaign,boolean isConfirm){

		if(isHasCampaign(campaign)){
			throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_REPEAT);
		}
		//查询出订单下所有策略的最大与最小时间
		Strategy strategy = sqlSessionHandler.selectOne("strategyMapper.strategy:time:range", campaign.getId());
		if(strategy!=null){
			if(!campaign.getStartTime().before(strategy.getEndTime())){
				//如果修改后的开始时间,都大于所有策略的结束时间抛出异常提示
				throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_RUNNING_NOTES);
			}else if(!strategy.getStartTime().before(campaign.getEndTime())){
				//抛出异常提示
				throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_RUNNING_NOTES);
			}
		}

		//FIXME 可以使用new Date()
		Date currDay = DateUtils.currDateDay();
		CampaignModel model = getCampaignById(campaign.getId());
		//判断是否需要更新对应的策略时间
		TimeUpdateModel timeModel1 = null,timeModel2 = null;
		//判断开始时间是否做出修改
		if(!campaign.getStartTime().equals(model.getStartTime())){
			if(model.getStartTime().before(currDay)||campaign.getStartTime().before(currDay)){
				//抛出错误订单开始时间小于当前日期不能做出修改
				throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_STARTDATE_WARNNING);
			}else{
				//开始时间
				timeModel1 = new TimeUpdateModel(model.getStartTime(),campaign.getStartTime(),campaign.getId());
			}
		}
		//结束时间是否做出修改
		if(!campaign.getEndTime().equals(model.getEndTime())){
			if(model.getEndTime().before(currDay)||campaign.getEndTime().before(currDay)){
				//抛出错误订单开始时间小于当前日期不能做出修改
				throw new CampaignValidateException(CampaignValidateException.ErrorCode.CAMPAIGN_ENDDATE_WARNNING);
			}else{
				//结束时间
				timeModel2 = new TimeUpdateModel(model.getEndTime(),campaign.getEndTime(),campaign.getId());
			}
		}
		
		// 查询出需要更新的策略ids
		String s1 = null, s2 = null;
		String s1_nom = null, s2_nom = null;
		if (timeModel1 != null && timeModel1.getCampaignStartUpdate()) {
			s1_nom = sqlSessionHandler.selectOne("strategyMapper.select:strategy:start:cannot:running", timeModel1);
			s1 = sqlSessionHandler.selectOne("strategyMapper.select:ids:by:campaign:start:time", timeModel1);
		}
		if (timeModel2 != null && timeModel2.getCampaignEndUpdate()) {
			s2_nom = sqlSessionHandler.selectOne("strategyMapper.select:strategy:end:cannot:running", timeModel2);
			s2 = sqlSessionHandler.selectOne("strategyMapper.select:ids:by:campaign:end:time", timeModel2);
		}
		
		String string = concatString(s1_nom, s2_nom);
		if(!StringUtils.isEmpty(string)){
			throw new StrategyRunningErrorException(string, "");
		}
		
		String ids = concatString(s1, s2);
		
		if (isConfirm) {
			if (!StringUtils.isEmpty(ids)) {
				throw new CampaignConfirmException(ids,"");
			}
		} else {
			if (!StringUtils.isEmpty(ids)) {
				if (timeModel1 != null&&!StringUtils.isEmpty(s1)) {
					String[] arr = s1.split(",");
					for(String str:arr){
						timeModel1.setStrategyId(str);
						sqlSessionHandler.update("strategyMapper.update:start:time", timeModel1);
					}
				}
				if (timeModel2 != null&&!StringUtils.isEmpty(s2)) {
					String[] arr = s2.split(",");
					for(String str:arr){
						timeModel2.setStrategyId(str);
						sqlSessionHandler.update("strategyMapper.update:end:time", timeModel2);
					}
				}
			}
		}

		sqlSessionHandler.update("campaignMapper.update", campaign);
		logger.info("编辑了订单{}({})",campaign.getName(),campaign.getId());
	}
	
	private String concatString(String s1, String s2){
		String ids = "";
		if (!StringUtils.isEmpty(s1)) {
			ids = s1;
		}
		if (!StringUtils.isEmpty(s2)) {
			if (!StringUtils.isEmpty(ids)) {
				ids = ids + "," + s2;
			} else {
				ids = s2;
			}
		}
		return ids;
	}
	
	/**
	 * 验证订单在广告主下是否存在重复
	 */
	public boolean isHasCampaign(Campaign campaign){

		return (int)sqlSessionHandler.selectOne("campaignMapper.campaign:checkname", campaign) > 0;
	}
	
	
	/**
	 * 订单删除, 虚拟删除，实际为update
	 */
	@Transactional
	public void deleteCampaign(Integer id) {
		getCampaignById(id);  //校验订单是否存在
		// 删除订单时，同时逻辑删除订单下的所有策略
		sqlSessionHandler.update("campaignMapper.delete", id);
		sqlSessionHandler.update("strategyMapper.delete", id);
		logger.info("删除了订单ID({})",id);
	}

	/**
	 * 订单状态更新, 待投放和投放中的订单可以暂停，已暂停的订单可以启用
	 */
	public CampaignModel updateCampaignStatus(Integer id, Integer status) {
		Map<String, Object> params = new HashMap<>(2);
		params.put("id", id);
		params.put("status", status);
		sqlSessionHandler.update("campaignMapper.update:status", params);
		logger.info("更改了订单状态ID{}状态值为{}",id,status);
		return getCampaignById(id);
	}

	/**
	 * 查询数据报告所需要的订单数据
	 */
	public ResultSetList<CampaignModel> getReportList(Map<String, Object> map, PageParameter page) {
		List<CampaignModel> campaignList = sqlSessionHandler.selectList("campaignMapper.campaign:report:list:page", map, page);
		return new ResultSetList<>(page.getTotalCount(), campaignList);

	}

	public List<DropDownModel> getTags() {
		return sqlSessionHandler.selectList("campaignTagMapper.selectAllTags",null);
	}

	public List<DropDownModel> getAgencyDrop() {
		return sqlSessionHandler.selectList("agencyMapper.selectAllAgencies",null);
	}
}
